from fastapi import FastAPI, HTTPException, status, Depends
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import HTTPBearer
from typing import List, Optional
from datetime import datetime, timedelta
from sqlalchemy.orm import Session

from models import (
    Todo, TodoCreate, TodoUpdate, TodoResponse, TodoListResponse,
    TodoStatus, TodoPriority, UserLogin, LoginResponse, Token, User,
    UserListResponse, AdminTodoCreate, UserRole,  # 添加管理员相关模型
    NotificationCreate, NotificationResponse, NotificationListResponse  # 添加通知相关模型
)
from database import get_db, create_tables
# 重要：导入所有数据库模型，确保 Base.metadata 包含所有表定义
from db_models import UserDB, TodoDB, NotificationDB
from todo_service import TodoService
from user_service import UserService, AdminService  # 添加用户和管理员服务
from notification_service import NotificationService  # 添加通知服务
from auth import (
    authenticate_user, create_access_token, get_current_user, get_current_admin,
    init_default_users, ACCESS_TOKEN_EXPIRE_MINUTES
)

# 创建 FastAPI 应用实例
app = FastAPI(
    title="待办事项 API",
    description="一个简单的待办事项管理 API 服务",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

# 在应用启动时创建数据库表和初始化用户
@app.on_event("startup")
def startup_event():
    create_tables()
    # 初始化默认用户
    db = next(get_db())
    try:
        init_default_users(db)
    finally:
        db.close()

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 在生产环境中应该设置为具体的域名
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/", summary="根路径")
async def root():
    """API 根路径，返回欢迎信息"""
    return {
        "message": "欢迎使用待办事项 API 服务!",
        "docs": "/docs",
        "version": "1.0.0"
    }

@app.get("/health", summary="健康检查")
async def health_check():
    """健康检查接口"""
    return {
        "status": "healthy",
        "message": "服务运行正常"
    }

@app.post("/auth/login", response_model=LoginResponse, summary="用户登录")
async def login(user_login: UserLogin, db: Session = Depends(get_db)):
    """
    用户登录接口
    
    - **username**: 用户名
    - **password**: 密码
    """
    user = authenticate_user(db, user_login.username, user_login.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    
    user_data = User(
        id=user.id,
        username=user.username,
        role=user.role,  # 添加角色字段
        created_at=user.created_at,
        updated_at=user.updated_at
    )
    
    token_data = Token(
        access_token=access_token,
        token_type="bearer",
        user=user_data
    )
    
    return LoginResponse(
        success=True,
        message="登录成功",
        data=token_data
    )

@app.get("/todos", response_model=TodoListResponse, summary="获取所有待办事项")
async def get_todos(
    status: Optional[TodoStatus] = None,
    priority: Optional[TodoPriority] = None,
    limit: Optional[int] = None,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取当前用户的所有待办事项列表
    
    - **status**: 可选，按状态过滤
    - **priority**: 可选，按优先级过滤  
    - **limit**: 可选，限制返回数量
    """
    try:
        db_todos = TodoService.get_all_todos(db, current_user.id, status, priority, limit)
        todos = [TodoService.convert_to_pydantic(db_todo) for db_todo in db_todos]
        
        return TodoListResponse(
            success=True,
            message=f"成功获取 {len(todos)} 条待办事项",
            data=todos,
            total=len(todos)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取待办事项失败: {str(e)}"
        )

@app.get("/todos/{todo_id}", response_model=TodoResponse, summary="获取单个待办事项")
async def get_todo(
    todo_id: int, 
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    根据ID获取当前用户的单个待办事项
    
    - **todo_id**: 待办事项的唯一标识符
    """
    db_todo = TodoService.get_todo_by_id(db, todo_id, current_user.id)
    if not db_todo:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"未找到ID为 {todo_id} 的待办事项"
        )
    
    todo = TodoService.convert_to_pydantic(db_todo)
    return TodoResponse(
        success=True,
        message="成功获取待办事项",
        data=todo
    )

@app.post("/todos", response_model=TodoResponse, summary="创建新的待办事项")
async def create_new_todo(
    todo: TodoCreate, 
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    为当前用户创建新的待办事项
    
    - **title**: 必填，待办事项标题
    - **description**: 可选，详细描述
    - **status**: 可选，状态 (pending/in_progress/completed)
    - **priority**: 可选，优先级 (low/medium/high)
    """
    try:
        db_todo = TodoService.create_todo(db, todo, current_user.id)
        new_todo = TodoService.convert_to_pydantic(db_todo)
        return TodoResponse(
            success=True,
            message="成功创建待办事项",
            data=new_todo
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"创建待办事项失败: {str(e)}"
        )

@app.put("/todos/{todo_id}", response_model=TodoResponse, summary="更新待办事项")
async def update_existing_todo(
    todo_id: int, 
    todo_update: TodoUpdate, 
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    更新当前用户的现有待办事项
    
    - **todo_id**: 待办事项的唯一标识符
    - **title**: 可选，新的标题
    - **description**: 可选，新的描述
    - **status**: 可选，新的状态
    - **priority**: 可选，新的优先级
    """
    # 检查待办事项是否存在
    existing_todo = TodoService.get_todo_by_id(db, todo_id, current_user.id)
    if not existing_todo:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"未找到ID为 {todo_id} 的待办事项"
        )
    
    # 只更新提供的字段
    update_data = todo_update.dict(exclude_unset=True)
    if not update_data:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="至少需要提供一个要更新的字段"
        )
    
    try:
        # 获取更新前的任务状态
        old_status = existing_todo.status
        
        updated_db_todo = TodoService.update_todo(db, todo_id, todo_update, current_user.id)
        updated_todo = TodoService.convert_to_pydantic(updated_db_todo)
        
        # 检查是否是任务完成状态变更
        new_status = updated_db_todo.status
        if (
            old_status != TodoStatus.COMPLETED and 
            new_status == TodoStatus.COMPLETED
        ):
            # 任务已完成，通知所有管理员
            try:
                admin_user_ids = NotificationService.get_admin_user_ids(db)
                if admin_user_ids:
                    NotificationService.create_task_completion_notification(
                        db, 
                        updated_todo.title,
                        current_user.username,
                        admin_user_ids
                    )
            except Exception as notification_error:
                # 通知失败不影响任务更新
                print(f"创建任务完成通知失败: {notification_error}")
        
        return TodoResponse(
            success=True,
            message="成功更新待办事项",
            data=updated_todo
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"更新待办事项失败: {str(e)}"
        )

@app.put("/todos/batch/reorder", summary="批量更新任务排序")
async def reorder_todos(
    order_updates: List[dict], 
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量更新当前用户的任务排序
    
    请求格式: [{"id": 1, "order": 0}, {"id": 2, "order": 1}, ...]
    """
    try:
        # 验证请求数据
        if not order_updates:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="请求数据不能为空"
            )
        
        # 批量更新排序
        updated_count = TodoService.reorder_todos(db, order_updates, current_user.id)
        
        return {
            "success": True,
            "message": f"成功更新 {updated_count} 个任务的排序",
            "updated_count": updated_count
        }
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"更新排序失败: {str(e)}"
        )

@app.delete("/todos/{todo_id}", response_model=TodoResponse, summary="删除待办事项")
async def delete_existing_todo(
    todo_id: int, 
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    删除当前用户的指定待办事项
    
    - **todo_id**: 待办事项的唯一标识符
    """
    # 检查待办事项是否存在
    existing_todo = TodoService.get_todo_by_id(db, todo_id, current_user.id)
    if not existing_todo:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"未找到ID为 {todo_id} 的待办事项"
        )
    
    # 检查是否为管理员分配的任务
    if existing_todo.assigned_by_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="不能删除管理员分配的任务，请联系管理员处理"
        )
    
    try:
        deleted_db_todo = TodoService.delete_todo(db, todo_id, current_user.id)
        deleted_todo = TodoService.convert_to_pydantic(deleted_db_todo)
        return TodoResponse(
            success=True,
            message="成功删除待办事项",
            data=deleted_todo
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"删除待办事项失败: {str(e)}"
        )

@app.post("/todos/reset", summary="重置用户数据库数据")
async def reset_database_data(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    重置当前用户的数据库数据，重新生成20条示例数据
    """
    try:
        # 清空现有数据并重新初始化
        count = TodoService.reset_with_mock_data(db, current_user.id)
        
        return {
            "success": True,
            "message": f"成功重置数据库数据，共 {count} 条",
            "total": count
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"重置数据失败: {str(e)}"
        )

@app.get("/todos/stats/summary", summary="获取待办事项统计信息")
async def get_todos_stats(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取当前用户待办事项的统计信息
    """
    try:
        stats = TodoService.get_stats(db, current_user.id)
        
        return {
            "success": True,
            "message": "成功获取统计信息",
            "data": stats
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取统计信息失败: {str(e)}"
        )

# ====== 管理员 API 接口 ======

@app.get("/admin/users", response_model=UserListResponse, summary="获取所有用户（管理员）")
async def get_all_users(
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员获取所有用户列表
    """
    try:
        db_users = UserService.get_all_users(db)
        users = [UserService.convert_to_pydantic(db_user) for db_user in db_users]
        
        return UserListResponse(
            success=True,
            message=f"成功获取 {len(users)} 个用户",
            data=users,
            total=len(users)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取用户列表失败: {str(e)}"
        )

@app.get("/admin/users/{user_id}/todos", response_model=TodoListResponse, summary="获取指定用户的任务（管理员）")
async def get_user_todos(
    user_id: int,
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员获取指定用户的所有任务
    """
    try:
        # 检查目标用户是否存在
        target_user = UserService.get_user_by_id(db, user_id)
        if not target_user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"未找到ID为 {user_id} 的用户"
            )
        
        db_todos = UserService.get_user_todos(db, user_id)
        todos = [TodoService.convert_to_pydantic(db_todo) for db_todo in db_todos]
        
        return TodoListResponse(
            success=True,
            message=f"成功获取用户 {target_user.username} 的 {len(todos)} 个任务",
            data=todos,
            total=len(todos)
        )
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取用户任务失败: {str(e)}"
        )

@app.post("/admin/users/{user_id}/todos", response_model=TodoResponse, summary="为用户分配任务（管理员）")
async def assign_todo_to_user(
    user_id: int,
    todo_data: TodoCreate,
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员为指定用户分配任务
    """
    try:
        # 检查目标用户是否存在
        target_user = UserService.get_user_by_id(db, user_id)
        if not target_user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"未找到ID为 {user_id} 的用户"
            )
        
        db_todo = AdminService.assign_todo_to_user(db, admin_user, todo_data, user_id)
        new_todo = TodoService.convert_to_pydantic(db_todo)
        
        # 创建任务分配通知
        try:
            NotificationService.create_task_assignment_notification(
                db, user_id, todo_data.title, admin_user.username
            )
        except Exception as notification_error:
            # 通知创建失败不影响任务分配
            print(f"通知创建失败: {notification_error}")
        
        return TodoResponse(
            success=True,
            message=f"成功为用户 {target_user.username} 分配任务，并发送通知",
            data=new_todo
        )
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"分配任务失败: {str(e)}"
        )

@app.get("/admin/todos", response_model=TodoListResponse, summary="获取所有任务（管理员）")
async def get_all_todos_admin(
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员获取系统中所有任务
    """
    try:
        db_todos = AdminService.get_all_todos(db)
        todos = [TodoService.convert_to_pydantic(db_todo) for db_todo in db_todos]
        
        return TodoListResponse(
            success=True,
            message=f"成功获取系统中所有 {len(todos)} 个任务",
            data=todos,
            total=len(todos)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取所有任务失败: {str(e)}"
        )

@app.delete("/admin/users/{user_id}/todos/{todo_id}", summary="删除用户任务（管理员）")
async def delete_user_todo_admin(
    user_id: int,
    todo_id: int,
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员删除指定用户的任务
    
    - **user_id**: 用户ID
    - **todo_id**: 任务ID
    """
    try:
        # 验证任务是否存在且属于指定用户
        todo = TodoService.get_todo_by_id(db, todo_id, user_id)
        if not todo:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"未找到用户 {user_id} 的任务 {todo_id}"
            )
        
        # 保存任务标题用于通知
        task_title = todo.title
        
        # 删除任务
        deleted_todo = TodoService.delete_todo(db, todo_id, user_id)
        if not deleted_todo:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"删除任务失败"
            )
        
        # 创建任务删除通知
        try:
            NotificationService.create_task_deletion_notification(
                db, user_id, task_title, admin_user.username
            )
        except Exception as notification_error:
            # 通知创建失败不影响任务删除
            print(f"删除通知创建失败: {notification_error}")
        
        return {
            "success": True,
            "message": f"成功删除用户 {user_id} 的任务 {todo_id}，并发送通知"
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"删除任务失败: {str(e)}"
        )

@app.get("/admin/statistics", summary="获取系统统计信息（管理员）")
async def get_admin_statistics(
    admin_user: UserDB = Depends(get_current_admin),
    db: Session = Depends(get_db)
):
    """
    管理员获取系统统计信息
    """
    try:
        stats = AdminService.get_user_statistics(db)
        return {
            "success": True,
            "message": "成功获取系统统计信息",
            "data": stats
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取统计信息失败: {str(e)}"
        )

# 通知相关API
@app.get("/notifications", response_model=NotificationListResponse, summary="获取用户通知")
async def get_user_notifications(
    limit: Optional[int] = 50,
    unread_only: bool = False,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取当前用户的通知列表
    """
    try:
        notifications = NotificationService.get_user_notifications(
            db, current_user.id, limit, unread_only
        )
        unread_count = NotificationService.get_unread_count(db, current_user.id)
        
        notification_list = [NotificationService.convert_to_pydantic(n) for n in notifications]
        
        return NotificationListResponse(
            success=True,
            message=f"成功获取 {len(notification_list)} 条通知",
            data=notification_list,
            total=len(notification_list),
            unread_count=unread_count
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取通知失败: {str(e)}"
        )

@app.put("/notifications/{notification_id}/read", summary="标记通知为已读")
async def mark_notification_read(
    notification_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    标记通知为已读
    """
    success = NotificationService.mark_as_read(db, notification_id, current_user.id)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="未找到指定通知"
        )
    
    return {
        "success": True,
        "message": "成功标记通知为已读"
    }

if __name__ == "__main__":
    import uvicorn
    
    print("🚀 启动待办事项 API 服务...")
    print("📖 API 文档: http://localhost:8000/docs")
    print("🔄 健康检查: http://localhost:8000/health")
    
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )